//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics.Contracts;
using System.Windows;
using System.Windows.Media;

namespace OpenLS.UI.Internals
{
    sealed class LayoutRounder
    {
        public LayoutRounder(FrameworkElement element)
        {
            Contract.Requires(element != null);
            Transform ft = Transform.Identity;
            Matrix matrix = ft.Value;
            FrameworkElement e = element;
            _offset = new Point(0, 0);
            while (e != null)
            {
                _offset = e.TranslatePoint(new Point(0, 0), element);
                var transform = e.RenderTransform;
                if (transform != null)
                    matrix = matrix * transform.Value;
                transform = e.LayoutTransform;
                if (transform != null)
                    matrix = matrix * transform.Value;
                e = VisualTreeHelper.GetParent(e) as FrameworkElement;
            }
            _offset = new Point(_offset.X - Math.Round(_offset.X), _offset.Y - Math.Round(_offset.Y));
            _offset = new Point(-_offset.X, -_offset.Y);
            try
            {
                PresentationSource source = PresentationSource.FromVisual(element);
                if (source != null)
                {
                    matrix = matrix * source.CompositionTarget.TransformToDevice;
                    _dpiX = matrix.M11;
                    _dpiY = matrix.M22;
                }

            }
            catch (Exception)
            {


            }
        }

        private static double roundValue(double value, double dpi, double offset)
        {
            if (((!areClose(dpi, 1.0) && !double.IsNaN(value)) && (!double.IsInfinity(value) && !areClose(value, double.MaxValue))) && !areClose(value, double.MinValue))
            {
                return Math.Round((value + offset) * dpi) / dpi - offset;
            }
            return Math.Round(value + offset) - offset;
        }

        private static bool areClose(double dpi, double p)
        {
            return Math.Abs(dpi - p) < 0.000000001;
        }


        private double roundYValue(double value)
        {
            if (_dpiY == null)
                return value;
            return roundValue(value, _dpiY.Value, _offset.Y);
        }

        private double roundXValue(double value)
        {
            if (_dpiX == null)
                return value;
            return roundValue(value, _dpiX.Value, _offset.X);
        }
        private double? _dpiX;
        private double? _dpiY;
        private Point _offset;

        internal Point RoundPoint(Point point)
        {
            return new Point(roundXValue(point.X), roundYValue(point.Y));
        }
        internal Point RoundLinePoint(Point point, double thickness)
        {
            return new Point(roundXValue(point.X)+thickness/2, roundYValue(point.Y)+thickness/ 2);
        }
        public Rect RoundRect(Rect rect)
        {
            double halfWidth = rect.Width / 2;
            double halfHeight = rect.Height / 2;
            double midX = roundXValue(rect.Left + halfWidth);
            double midY = roundYValue(rect.Top + halfHeight);
            var result = new Rect(midX - halfWidth, midY - halfHeight, rect.Width, rect.Height);
            return result;
        }
    }
}
